﻿using System;
using System.Collections.Generic;
using oModbus.Device;
using oModbus.Message;
using oModbus.Utility;

namespace oModbus
{
    /// <summary>
    /// 主机
    /// </summary>
    public class ModbusMaster
    {
        /// <summary>
        /// 从机Id
        /// </summary>
        public byte SlaveId { get; set; }
        /// <summary>
        /// 传输接口
        /// </summary>
        private readonly ITransmission _transmission;
        public ModbusMaster(byte unitId, ITransmission transmission)
        {
            SlaveId = unitId;
            _transmission = transmission;
            //_transmission = new SerialTransmission(port);
            _transmission.ReceivedMessageEvent += _transmission_ReceivedMessageEvent;
        }
        /// <summary>
        /// 校验
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private bool Verification(byte[] data)
        {
            byte[] crc1 = new List<byte>() { data[data.Length - 2], data[data.Length - 1] }.ToArray();
            List<byte> temp = new List<byte>();
            for (int i = 0; i < data.Length - 2; i++)
            {
                temp.Add(data[i]);
            }
            byte[] crc2 = temp.ToArray().CalculateCrc();
            return crc1[0] == crc2[0] && crc1[1] == crc2[1];

        }
        /// <summary>
        /// 接受数据
        /// </summary>
        /// <param name="data"></param>
        private void _transmission_ReceivedMessageEvent(byte[] data)
        {
            if (data.Length > 4)
            {
                //if(true)
                if (Verification(data))
                {
                    ReceivedMessageEvent?.Invoke(data);
                    switch ((FunctionCode)data[1])
                    {
                        case FunctionCode.ReadCoil:

                            Handle(new ReadCoilResponse(data));
                            break;
                        case FunctionCode.ReadDiscreteInput:
                            Handle(new ReadDiscreteInputResponse(data));
                            break;
                        case FunctionCode.ReadHoldRegister:
                            Handle(new ReadHoldRegisterResponse(data));
                            break;
                        case FunctionCode.ReadInputRegister:
                            Handle(new ReadInputRegisterResponse(data));
                            break;
                        case FunctionCode.WriteSingleCoil:
                            Handle(new WriteSingleCoilResponse(data));
                            break;
                        case FunctionCode.WriteSingleRegister:
                            Handle(new WriteSingleRegisterResponse(data));
                            break;
                        case FunctionCode.WriteMultipleCoil:
                            Handle(new WriteMultipleCoilResponse(data));
                            break;
                        case FunctionCode.WriteMultipleRegister:
                            Handle(new WriteMultipleRegisterResponse(data));
                            break;
                        case FunctionCode.ReadFileRecord:
                            // Handle(new ReadFileRecordResponse(data));
                            break;
                        case FunctionCode.WriteFileRecord:
                            // Handle(new WriteFileRecordResponse(data));
                            break;
                        case FunctionCode.MaskWriteRegister:
                            //Handle(new MaskWriteRegisterResponse(data));
                            break;
                        case FunctionCode.ReadDeviceId:

                            // Handle(new ReadDeviceIdResponse(data));
                            break;
                        case FunctionCode.Error:

                            // Handle(new ErrorResponse(data));
                            break;
                            //default:
                            //    throw new ArgumentOutOfRangeException();
                    }
                }
                else
                {
                    //没有车型
                }
            }
            else
            {
                //内容不对
            }
            //Show(data);
        }
        public void Close()
        {
            _transmission.Close();
        }
        public void HandleBase(AbstractModbusMessage message)
        {
            _transmission.Send(message);
        }
        public void Send(AbstractModbusMessage message)
        {
            SendMessageEvent?.Invoke(message.PackingMessage());
            _transmission.Send(message);
        }
        public event Action<byte[]> ReceivedMessageEvent;
        public event Action<byte[]> SendMessageEvent;
        public event Action<ReadCoilResponse> ReadCoilEvent;
        private void Handle(ReadCoilResponse message)
        {
            ReadCoilEvent?.Invoke(message);
        }

        public event Action<ReadDiscreteInputResponse> ReadDiscreteInputEvent;
        private void Handle(ReadDiscreteInputResponse message)
        {
            ReadDiscreteInputEvent?.Invoke(message);

        }
        public event Action<ReadHoldRegisterResponse> ReadHoldRegisterEvent;

        private void Handle(ReadHoldRegisterResponse message)
        {
            ReadHoldRegisterEvent?.Invoke(message);

        }
        
        public event Action<ReadInputRegisterResponse> ReadInputRegisterEvent;
        private void Handle(ReadInputRegisterResponse message)
        {
            ReadInputRegisterEvent?.Invoke(message); 
        }

        public event Action<WriteSingleCoilResponse> WriteSingleCoilEvent;

        private void Handle(WriteSingleCoilResponse message)
        {
            WriteSingleCoilEvent?.Invoke(message); 
        }

        public event Action<WriteSingleRegisterResponse> WriteSingleRegisterEvent;

        private void Handle(WriteSingleRegisterResponse message)
        {
            WriteSingleRegisterEvent?.Invoke(message); 
        }
        public event Action<WriteMultipleCoilResponse> WriteMultipleCoilEvent;

        private void Handle(WriteMultipleCoilResponse message)
        {
            WriteMultipleCoilEvent?.Invoke(message);

        }
        public event Action<WriteMultipleRegisterResponse> WriteMultipleRegisterEvent;

        private void Handle(WriteMultipleRegisterResponse message)
        {
            WriteMultipleRegisterEvent?.Invoke(message);
        }
    }
}
